import Random from "js/core/random";
import utils from "js/core/utils";
import { EffectModel, FighterAttriModel, FighterModel, SkillModel, TeamSkillModel } from "js/model/fighterModel";
import { PlayerModel } from "js/model/playerModel";
import { AttackType, BattleResult, HurtType, MapType, MonsterType, TeamID, TriggerType } from "js/typeDefine/typeDefine";
import fighterHandle from "./fighterHandle";
import monsterHandle from "./monsterHandle";
import TimerHandle from "./timerHandle";
import { gameConfig, gameConfigHandle, propName } from "js/config/gameConfig";
import BattleSkillHandle, { TriggerEffectDataModel } from "./battleSkillHandle";
import { CalcDamageDataModel } from "js/model/battleModel";
import partnerHandle from "./partnerHandle";
import { PartnerModel } from "js/model/partnerModel";
import gameUtils from "js/core/gameUtils";

export default class BattleHandle {
    rand: Random
    pet: FighterModel
    player: PlayerModel
    team1: FighterModel[]
    team2: FighterModel[]
    team3: FighterModel[]  //i
    team4: FighterModel[]  //i
    shenqiL: FighterModel//i
    shenqiR: FighterModel//i
    battleSkillHandle: BattleSkillHandle
    teamIndexID: number
    timerHandle: TimerHandle
    team1Skills: TeamSkillModel[]
    fighterNodes: any
    fighterBgNodes: any
    update: any
    mapID: number
    mapType: MapType //1普通,2副本,3深渊
    floor: number
    monsterLvl: number
    monsterInitAmount: number
    monsterAmount: number
    monsterMaxAmount: number
    monsterAliveAmount: number
    monsterDead: any
    monsters: any
    battleCb: any
    isEnd: boolean
    battleTimeMax: number//战斗时间上限
    timeOver: boolean//战斗超时
    remainder: number//剩余战斗时间
    calcDamageFlag: boolean // 统计伤害
    pause: boolean
    playerBattle: boolean
    damageCoe: number
    constructor(seed?: number) {
        this.teamIndexID = 1   //队伍中成员的编号
        this.rand = new Random(seed || new Date().getTime())
        this.timerHandle = new TimerHandle()
        this.fighterNodes = {}
        this.fighterBgNodes = {}
        this.monsterAmount = 0
        this.monsterMaxAmount = 8
        this.monsterAliveAmount = 0
        this.battleSkillHandle = new BattleSkillHandle(this)
        this.isEnd = false
        this.monsterDead = {}
        this.monsters = {}
        this.mapType = 1
        this.battleTimeMax = 600000//默认最长战斗时间 20分钟
        this.timeOver = false
        this.remainder = 600000
        this.calcDamageFlag = false
        this.pause = false
        this.playerBattle = false
        this.damageCoe = 100
        this.team1Skills = []
    }

    initTeam(player: PlayerModel, mapID: number, floor?: number) {
        this.mapID = mapID
        let mapItemConfig = gameConfigHandle.configByID[this.mapID]
        this.mapType = mapItemConfig.mapType
        //角色队伍
        this.team1 = new Array(12).fill(null)
        let team = player.teamList.list || []
        let idx = 0
        new Array(12).fill(1).forEach((_, i) => {
            let partner = team.find(p => p && p.formationPos == i)
            if (!partner) {
                return
            }
            let partnerFighter = partnerHandle.createPartnerFighter(player, partner)
            partnerFighter.indexID = partner.index
            partnerFighter.teamID = TeamID.Team1
            let poss = i
            let { x, y } = this.getXY(poss)
            partnerFighter.battlePos = x + 12
            partnerFighter.battleY = y
            partnerHandle.getDefaultSkill(partner, partnerFighter)
            this.team1[poss] = (partnerFighter)
            idx++
        })
        let activeLinkage: any = null
        gameConfig.baseFormation.linkageList.forEach((l, i) => {
            let activeLinkageRoles = partnerHandle.activeLinkageRoles(player, l.skillID, l.roles)
            if (activeLinkageRoles.activeLvl > 0 && player.formation.activeLinkage == i) {
                if (activeLinkage && activeLinkage.activeLvl < activeLinkageRoles.activeLvl) {
                    activeLinkage = activeLinkageRoles
                } else {
                    activeLinkage = activeLinkageRoles
                }
            }
        })
        if (activeLinkage) {
            let skillConfig = gameConfigHandle.configByID[activeLinkage.skillID]
            let teamSkill = new TeamSkillModel({ cd: skillConfig.cd, triggerTime: 0 })
            let skill = new SkillModel({ skillID: activeLinkage.skillID, skillLvl: activeLinkage.activeLvl, cd: skillConfig.cd, firstCd: skillConfig.firstTriggerCd })
            skill.triggerLimitTimes = skillConfig.triggerLimitTimes || 0
            teamSkill.skill = skill
            if (activeLinkage.roles) {
                let linkagePartners: PartnerModel[] = player.teamList.list.filter(p => p && activeLinkage.roles.findIndex(r => r == p.tID)).sort((p1, p2) => {
                    return p2.fighter.power - p1.fighter.power
                })
                let teamAttack = 0
                activeLinkage.roles.forEach(r => {
                    let p = linkagePartners.find(p => p.tID == r)
                    if (p) {
                        teamAttack += p.fighter.battleAttri.attack
                    }
                })
                teamSkill.teamAttack = teamAttack
            }
            this.team1Skills.push(teamSkill)
        }

        this.floor = floor || player.adventureInfo.floor
        let mapConfig = gameConfigHandle.gameConfig.map
        let mapLvl = mapItemConfig.mapLvl
        if (mapItemConfig.mapType == MapType.Normal) {
            let { floor } = gameUtils.getMapMax(player.baseInfo.mapProgressMax)
            this.floor = floor
            this.monsterLvl = mapLvl + (this.floor - 1) * 2
            this.monsterMaxAmount = utils.getIncValue(mapConfig.monsterAmount, this.monsterLvl)
            let initAdd = Math.floor(this.monsterMaxAmount / 2)
            if (initAdd > 12) {
                initAdd = 12
            }
            if (initAdd < 1) {
                initAdd = 1
            }
            this.monsterInitAmount = initAdd
        } else if (mapItemConfig.mapType == MapType.Deep) {
            this.monsterLvl = mapItemConfig.mapLvl
            this.monsterMaxAmount = mapItemConfig.monsterMaxAmount
            this.monsterInitAmount = mapItemConfig.monsterInitAmount
        } else if (mapItemConfig.mapType == MapType.WorldBoss) {
            let bossFloor = 1
            this.monsterLvl = utils.getIncValue(mapLvl, bossFloor - 1)
            this.monsterMaxAmount = mapItemConfig.monsterMaxAmount
            this.monsterInitAmount = mapItemConfig.monsterInitAmount
        } else if (mapItemConfig.mapType == MapType.Boss) {
            let bossFloor = 1
            this.monsterLvl = utils.getIncValue(mapLvl, bossFloor - 1)
            this.monsterMaxAmount = mapItemConfig.monsterMaxAmount
            this.monsterInitAmount = mapItemConfig.monsterInitAmount
        } else if (mapItemConfig.mapType == MapType.Night) {
            let floor = player.deepInfo.nightTodayProgress || 1
            this.monsterLvl = utils.getIncValue(mapLvl, floor)
            this.monsterMaxAmount = mapItemConfig.monsterMaxAmount
            this.monsterInitAmount = mapItemConfig.monsterInitAmount
        } else if (mapItemConfig.mapType == MapType.Fantasy) {
            let floor = player.adventureInfo.newFloor
            this.monsterLvl = mapItemConfig.mapLvl + floor - 1
            this.monsterMaxAmount = utils.getIncValue(mapConfig.monsterAmount, this.monsterLvl)
            let initAdd = Math.floor(this.monsterMaxAmount / 2)
            if (initAdd > 12) {
                initAdd = 12
            }
            if (initAdd < 1) {
                initAdd = 1
            }
            // this.monsterAmount = initAdd
            this.monsterInitAmount = initAdd
        }
        if (this.monsterMaxAmount > 12 && mapItemConfig.mapType != MapType.Deep) {
            this.monsterMaxAmount = 12
        }
        //敌方队伍
        this.team2 = new Array(12).fill(null)
        this.battleCb({ type: 2, value: [this.monsterAmount, this.monsterAliveAmount, this.monsterMaxAmount] })
    }

    setUpdate(update) {
        this.update = update
    }
    setDamageCoe(coe: number) {
        this.damageCoe = coe || 100
    }
    setCb(cb) {
        this.battleCb = cb
    }
    async start() {
        try {
            let oTimer = this.timerHandle
            this.timerHandle = new TimerHandle()
            this.timerHandle.timeCoe = oTimer.timeCoe
            this.timerHandle.start()
            this.timerHandle.setTimeout(async () => {
                this.team1.filter(p => p && p.battleAttri.hp > 0).forEach(p => {
                    this.battleUpdate()
                    this.timerHandle.setTimeout(async () => {
                        if (this.pause) {
                            this.timerHandle.stop()
                        }
                        this.startAttack(p)
                        this.recoverHp(p)
                        // this.recoverAnger(p)
                        //技能攻击开始
                        for (let i = 0; i < p.skills.length; i++) {
                            let skill = p.skills[i]
                            this.battleSkillHandle.startUseSkill(p, skill)
                        }
                    }, 100)

                })
            }, 300)
            if (this.playerBattle) {
                this.timerHandle.setTimeout(async () => {
                    this.team2.filter(p => p && p.battleAttri.hp > 0).forEach(p => {
                        this.battleUpdate()
                        this.timerHandle.setTimeout(async () => {
                            if (this.pause) {
                                this.timerHandle.stop()
                            }
                            this.startAttack(p)
                            this.recoverHp(p)
                            // this.recoverAnger(p)
                            //技能攻击开始
                            for (let i = 0; i < p.skills.length; i++) {
                                let skill = p.skills[i]
                                this.battleSkillHandle.startUseSkill(p, skill)
                            }
                        }, 5000)

                    })
                }, 300)
            }
            let mapComfig = gameConfigHandle.configByID[this.mapID]
            if (this.team1Skills.length > 0 && mapComfig.mapType != MapType.Fantasy) {
                this.timerHandle.setTimeout(async () => {
                    this.team1Skills.forEach(ts => {
                        this.timerHandle.setTimeout(async () => {
                            let fighter = new FighterModel({ battleAttri: new FighterAttriModel({ attack: ts.teamAttack }) })
                            let skillConfig = gameConfigHandle.configByID[ts.skill.skillID]
                            if (skillConfig.triggers) {
                                skillConfig.triggers.forEach(triggerItem => {
                                    if (ts.skill.skillLvl >= triggerItem.limitLvl || !triggerItem.limitLvl) {
                                        let trigger = new EffectModel({
                                            skillID: ts.skill.skillID,
                                            type: triggerItem.triggerType,
                                            skillLvl: ts.skill.skillLvl,
                                            data: JSON.parse(JSON.stringify(triggerItem))
                                        })
                                        if (!fighter.effects[triggerItem.triggerType]) {
                                            fighter.effects[triggerItem.triggerType] = []
                                        }
                                        fighter.effects[triggerItem.triggerType].push(trigger)
                                    }
                                })
                            }
                            await this.battleSkillHandle.startUseSkill(fighter, ts.skill, true)
                            ts.triggerTime = 1
                        }, 100)
                    })
                }, 300)
            }

            if (!this.playerBattle) {
                let timerID = this.timerHandle.setInterval(() => {
                    if (this.monsterInitAmount > 0) {
                        this.monsterInitAmount -= 1
                        this.addMonster(1)
                    } else {
                        this.timerHandle.clearTimeout(timerID)
                    }
                }, 150)


                //添加敌人
                let addMonsterTimerID = this.timerHandle.setInterval(async () => {
                    if (this.monsterAmount >= this.monsterMaxAmount) {
                        this.timerHandle.clearTimeout(addMonsterTimerID)
                    } else {
                        await this.addMonster()
                    }
                    Object.entries(this.fighterNodes).forEach(fn => {
                        let exists = Object.entries(this.monsters).find(m => m && m[1]['indexID'] == fn[0])
                        if (exists) {
                            if (exists[1]['teamID'] == 2 && exists[1]['battleAttri'].hp < 1) {
                                let node: any = fn[1]
                                node?.hideAnimation(() => {
                                    delete this.fighterNodes[fn[0]]
                                })
                            }
                        } else if (!exists) {
                            let node: any = fn[1]
                            node?.hideAnimation(() => {
                                delete this.fighterNodes[fn[0]]
                            })
                        }
                    });
                }, 5000)
            }

            //战斗超时判断
            let battleTimeTimerID = this.timerHandle.setTimeout(async () => {
                this.timeOver = true
                this.battleCb({ type: 1, value: { result: BattleResult.timeOver, monsterAmount: this.monsterAmount, monsterAliveAmount: this.monsterAliveAmount, monsterMaxAmount: this.monsterMaxAmount } })
                this.timerHandle.stop()
            }, this.battleTimeMax)

            let remainderTimerID = this.timerHandle.setInterval(async () => {
                if (this.timeOver) {
                    this.timerHandle.clearTimeout(remainderTimerID)
                } else {
                    this.remainder -= 100
                    if (this.remainder < 0) {
                        this.remainder = 0
                        this.battleCb({ type: 1, value: { result: BattleResult.timeOver, monsterAmount: this.monsterAmount, monsterAliveAmount: this.monsterAliveAmount, monsterMaxAmount: this.monsterMaxAmount } })
                        this.timerHandle.stop()
                        this.timerHandle.clearTimeout(remainderTimerID)
                    }
                }
            }, 100)
        } catch (error) {
            console.log(error)
        }
    }

    async startAttack(attacker: FighterModel) {
        if (attacker && attacker.battleAttri.hp >= 1) {
            let attackSpeed = attacker.battleAttri.attackSpeed || 100
            // 判断是否限制速度
            let limit = attacker.battleAttri.attackLimit == null ? true : attacker.battleAttri.attackLimit
            let attackInterval = this.getAttackInterval(attackSpeed, limit)
            this.startAttackAnimation(attacker.indexID, attackInterval / 1000)
            let timerID = this.timerHandle.setTimeout(() => {
                this.attackAnimation(attacker.indexID)
                this.findDefenders(attacker, 1)
                this.startAttack(attacker)
                this.speedAnimation(attacker.indexID)
            }, () => {
                let limit = attacker.battleAttri.attackLimit == null ? true : attacker.battleAttri.attackLimit
                let attackSpeed = attacker.battleAttri.attackSpeed || 100
                let interval = this.getAttackInterval(attackSpeed, limit)
                return interval
            })
            attacker.timerObject['attack'] = timerID
        }
    }

    async recoverHp(attacker: FighterModel) {
        let timerID = this.timerHandle.setInterval(() => {
            if (attacker.battleAttri.hp >= 1) {
                let recoverValue = attacker.battleAttri.recoverHp + attacker.battleAttri.recoverHpPer * attacker.battleAttri.maxHp
                if (recoverValue > 0) {
                    let damageData = new CalcDamageDataModel()
                    damageData.addHpName = '恢复'
                    this.addHp(attacker, recoverValue, damageData)
                }
            }
        }, 5000)
        attacker.timerObject['recoverHp'] = timerID
    }

    async recoverAnger(attacker: FighterModel) {
        let timerID = this.timerHandle.setInterval(() => {
            if (attacker.battleAttri.hp >= 1) {
                let recoverValue = gameConfigHandle.gameConfig.partner.recoverAnger
                if (recoverValue > 0) {
                    let damageData = new CalcDamageDataModel()
                    damageData.addHpName = '怒气'
                    this.addAnger(attacker, recoverValue, damageData)
                }
            }
        }, 3000)
        attacker.timerObject['recoverAnger'] = timerID
    }

    async findDefenders(attacker: FighterModel, attackAmount: number) {
        let hatredType = attacker.hatredType || 1
        let defenders = this.calcHarted(attacker, attackAmount, null, hatredType)
        for (let i = 0; i < defenders.length; i++) {
            let defender = defenders[i]
            let damageData = new CalcDamageDataModel()
            damageData.attacker = attacker
            damageData.hurtType = attacker.battleAttri.hurtType
            this.normalAttack(attacker, defender, damageData)
        }
    }
    async normalAttack(attacker: FighterModel, defender: FighterModel, damageData: CalcDamageDataModel) {
        let isDodge = await this.isDodge(attacker, defender)
        if (isDodge) {
            this.beAttackAnimation(defender.indexID, 0, '闪避', damageData.hurtType)
            let triggerEffectData1 = new TriggerEffectDataModel()
            await this.battleSkillHandle.triggerEffects(defender, TriggerType.DodgeAfter, defender, triggerEffectData1)
            return
        }
        if (attacker.type == MonsterType.Partner) {
            this.battleSkillHandle.addAnger(attacker, attacker.battleAttri.addAnger || gameConfigHandle.gameConfig.battle.getAnger)
        }
        let { hurt, isCrit, realDamage } = await this.calcDamage(attacker, defender, damageData)
        await this.decHp(defender, hurt, damageData)
        if (damageData.attackType == AttackType.Normal && attacker && (attacker.battleAttri.bloodHpPer || attacker.battleAttri.bloodHp)) {
            let bloodHpPer = attacker.battleAttri.bloodHpPer || 0
            if (bloodHpPer > 20) {
                bloodHpPer = 20
            }
            let bloodHp = hurt * bloodHpPer / 100 + (attacker.battleAttri.bloodHp || 0)
            if (bloodHp > 0) {
                let recoverData = new CalcDamageDataModel({})
                recoverData.addHpName = '吸血'
                this.addHp(attacker,bloodHp, recoverData)
            }
        }
        if (realDamage && defender.battleAttri.hp > 0) {
            damageData.hurtType = HurtType.Real
            damageData.decHpName = '真实伤害'
            damageData.isCrit = false
            await this.decHp(defender, realDamage, damageData)
        }
        if (attacker.type == MonsterType.Partner) {
            this.playSound("attack")
        }
        return hurt
    }

    async calcDamage(attacker: FighterModel, defender: FighterModel, damageData: CalcDamageDataModel) {
        let { isCrit, critHurt } = await this.isCrit(attacker, defender, damageData.attackType)
        if (isCrit) {
            let triggerEffectData1 = new TriggerEffectDataModel()
            triggerEffectData1.calcDamageData = damageData
            await this.battleSkillHandle.triggerEffects(attacker, TriggerType.CritPre, defender, triggerEffectData1)
        }
        damageData.isCrit = isCrit
        let defRatio = this.calcDefRatio(attacker, defender, damageData.hurtType,
            damageData.skill ? damageData.skill.reduceDef : 0,
            damageData.skill ? damageData.skill.reduceAllDef : 0)
        let hurtTypeRatio = this.calcHurtTypeRatio(attacker, defender, damageData.hurtType,
            damageData.skill ? damageData.skill.reduceDef : 0,
            damageData.skill ? damageData.skill.reduceAllDef : 0)
        let reduceHurt = 0, addHurt = 0
        if (damageData.attackType == AttackType.Normal) {
            reduceHurt = defender.battleAttri.reduceAttackHurt || 0
            addHurt = attacker.battleAttri.addAttackHurt || 0
        } else if (damageData.attackType == AttackType.Skill) {
            reduceHurt = defender.battleAttri.reduceSkillHurt || 0
        }
        let hurt = attacker.battleAttri.attack *
            (1 + addHurt / 100) *
            (1 - defRatio / 100) *
            (damageData.attackHurtCoe / 100) *
            (1 - reduceHurt / 100) *
            (1 + critHurt / 100) *
            (1 + damageData.hurtInc / 100) *
            (1 + damageData.hurtDec / 100) *
            (1 + hurtTypeRatio / 100) *
            (1 - defender.battleAttri.reduceHurt / 100)

        //状态增加伤害
        Object.entries(attacker.statusHurtPer).forEach(item => {
            let statuId = item[0]
            let value: any = item[1]
            if (defender.status[statuId]) {
                hurt *= (1 + value / 100)
            }
        })
        //状态减伤害
        Object.entries(defender.statusReduceHurt).forEach(item => {
            let statuId = item[0]
            let value: any = item[1]
            if (attacker.status[statuId]) {
                hurt *= (1 - value / 100)
            }
        })
        if (damageData.skill) {
            if (damageData.skill.angerHurtPer) {
                let angerHurtPer = damageData.skill.angerHurtPer * this.battleSkillHandle.getNeedAnger(damageData.skill)
                hurt *= (1 + angerHurtPer / 100)
            }

            if (damageData.skill.cdAddHurt1) {
                let cdHurtPer = fighterHandle.calcCdHurtPer(damageData.skill.cd, damageData.skill.cdAddHurt1, damageData.skill.cdAddHurt2)
                hurt *= (1 + cdHurtPer / 100)
            }

            let skill = damageData.skill
            hurt *= (1 + skill.hurtPer / 100)
            if (defender.type == MonsterType.Boss && skill.bossHurtPer) {
                hurt *= (1 + skill.bossHurtPer / 100)
            }
            if (skill.hpHurtPer && (defender.battleAttri.hp / defender.battleAttri.maxHp * 100) < skill.hpHurtPer[0]) {
                hurt *= (1 + skill.hpHurtPer[1] / 100)
            }

            //技能增加伤害
            if (attacker.skillsHurtPer[skill.skillID]) {
                hurt *= (1 + attacker.skillsHurtPer[skill.skillID] / 100)
            }

            if (defender.type == MonsterType.Normal && skill.killMonsterPer) {
                if (this.rand.intn(100) <= skill.killMonsterPer) {
                    damageData.decHpName = "秒杀"
                    hurt = defender.battleAttri.hp + 1
                }
            }
        }

        hurt = Math.floor(hurt)
        if (this.damageCoe && defender.teamID == 1) {
            hurt = Math.floor(hurt * this.damageCoe / 100)
        }
        let triggerEffectData2 = new TriggerEffectDataModel()
        triggerEffectData2.calcDamageData = damageData
        this.battleSkillHandle.triggerEffects(attacker, TriggerType.DamageAfter, null, triggerEffectData2)
        let realDamage = null
        if (attacker.battleAttri.realHurt > 0 && damageData.attackType == AttackType.Normal) {
            realDamage = attacker.battleAttri.attack * attacker.battleAttri.realHurt / 100
            let antiRealHurt = defender.battleAttri.antiRealHurt
            if (antiRealHurt > 0) {
                antiRealHurt = antiRealHurt > 100 ? 100 : antiRealHurt
            }
            realDamage = Math.floor((1 - antiRealHurt / 100) * realDamage) || null
        }
        return { hurt: hurt, isCrit, realDamage }
    }

    async isDodge(attacker: FighterModel, defender: FighterModel) {
        let hit = attacker.battleAttri.hit
        let dodge = defender.battleAttri.dodge
        // let dodgeRatio = dodge - hit
        let dodgeRatio = (1 - (hit + 100) / (dodge + 100) * 0.8) * 100
        // 旧公式下, 限制无脑堆闪避, 在怪物等级超过900时, 强行限制闪避率
        // if (attacker.lvl > 900) {
        //     dodgeRatio = dodgeRatio > 90 ? 90 : dodgeRatio
        // }
        // 新公式
        // let dodgeRatio = (dodge + defender.lvl * 0.5) / (attacker.lvl * 0.5 + hit) * 100
        // if (attacker.tID == 0) {
        //     dodgeRatio = 70
        // }
        let mapComfig = gameConfigHandle.configByID[this.mapID]
        if (mapComfig && mapComfig.mapType == MapType.Fantasy) {
            dodgeRatio = (dodge + defender.lvl) / (attacker.lvl * 5 + hit) * 100
        }
        if (dodgeRatio > 90) {
            dodgeRatio = 90
        } else if (dodgeRatio < 0) {
            dodgeRatio = 0
        }
        let isDodge = dodgeRatio > this.rand.intn(100) ? true : false
        return isDodge
    }

    async isCrit(attacker: FighterModel, defender: FighterModel, attackType: AttackType) {
        let critRatio = attacker.battleAttri.crit - defender.battleAttri.antiCrit
        if (this.rand.intn(100) < critRatio) {
            let critHurt = attacker.battleAttri.critHurt - defender.battleAttri.antiCritHurt
            if (critHurt < 50) {
                critHurt = 50
            }
            if (attackType == AttackType.Skill) {
                critHurt = critHurt / 2
            }
            return { isCrit: true, critHurt: 100 + critHurt }
        } else {
            return { isCrit: false, critHurt: 0 }
        }
    }

    calcDefRatio(attacker: FighterModel, defender: FighterModel, hurtType: HurtType,
        reduceDefPer: number, reduceAllDef: number) {
        let def = defender.battleAttri.def
        let defRatio = 0
        // 新公式
        defRatio = (def + defender.lvl * 15) / (def + 15 * attacker.lvl + 400) * 100
        if (defRatio > 90) {
            defRatio = 90
        } else if (defRatio < 50) {
            defRatio = 50
        }

        return defRatio
    }

    calcHurtTypeRatio(attacker: FighterModel, defender: FighterModel, hurtType: HurtType,
        reduceDefPer: number, reduceAllDef: number) {
        let hurtTypePer = 0
        // if (hurtType !== HurtType.Normal) {
        //     if (hurtType == HurtType.Fire) {
        //         hurtTypePer = attacker.battleAttri.fHurt - defender.battleAttri.fDef + reduceAllDef
        //     } else if (hurtType == HurtType.Lightning) {
        //         hurtTypePer = attacker.battleAttri.lHurt - defender.battleAttri.lDef + reduceAllDef
        //     } else if (hurtType == HurtType.Posion) {
        //         hurtTypePer = attacker.battleAttri.sHurt - defender.battleAttri.sDef + reduceAllDef
        //     }
        //     if (hurtTypePer < -50) {
        //         hurtTypePer = -50
        //     }
        // }

        return hurtTypePer
    }

    async addHp(affecteder: FighterModel, value: number, damageData: CalcDamageDataModel) {
        affecteder.battleAttri.hp += value
        if (affecteder.battleAttri.hp >= affecteder.battleAttri.maxHp) {
            affecteder.battleAttri.hp = affecteder.battleAttri.maxHp
        }
        let name = damageData.addHpName || (damageData.skillID ? propName[damageData.skillID] : '')
        this.recoverAnimation(affecteder.indexID, value, name, damageData.isCrit, damageData.decHpAnimationDelay)
        if (affecteder.type == MonsterType.Partner) {
            this.playSound("recover")
        }
        let mapConfig = gameConfigHandle.configByID[this.mapID]
        if (this.calcDamageFlag && mapConfig.mapType == MapType.Fantasy) {
            this.battleCb({ type: 3, value: { affecteder, cureValue: value, damageData } })
        }
    }

    async addAnger(affecteder: FighterModel, value: number, damageData: CalcDamageDataModel) {
        affecteder.anger += value
        if (affecteder.anger >= affecteder.battleAttri.angerMax) {
            affecteder.anger = affecteder.battleAttri.angerMax
        }
        let name = damageData.addHpName || (damageData.skillID ? propName[damageData.skillID] : '')
        this.recoverAnimation(affecteder.indexID, value, name, damageData.isCrit, damageData.decHpAnimationDelay)
        if (affecteder.type == MonsterType.Partner) {
            this.playSound("recover")
        }
    }

    damageScale(value) {
        let coe = 100
        let remainPer = Math.floor((this.battleTimeMax - this.remainder) / this.battleTimeMax * 100)
        if (remainPer > 10) {
            coe += (remainPer - 10) * 10
        }
        let damage = value * coe / 100
        damage = damage <= 0 ? 1 : damage
        return damage || 1
    }

    async decHp(affecteder: FighterModel, value: number, damageData: CalcDamageDataModel, killAttackTimes: number = 0) {
        value = this.damageScale(value)
        value = Math.floor(value || 0)
        if (affecteder.battleAttri.hp < 1) {
            return
        }
        let name = damageData.decHpName || (damageData.skillID ? propName[damageData.skillID] : '')
        if (affecteder.battleAttri.shield >= value) {
            affecteder.battleAttri.shield -= value
            this.beAttackAnimation(affecteder.indexID, value, name, damageData.hurtType, damageData.isCrit, damageData.isDodge, damageData.decHpAnimationDelay, affecteder.battlePos)
            this.playSound("shieldUse")
            return
        }
        else if (affecteder.battleAttri.shield > 0) {
            value -= affecteder.battleAttri.shield
            affecteder.battleAttri.shield = 0
            this.playSound("shieldUse")
        }
        affecteder.battleAttri.hp -= value
        let mapConfig = gameConfigHandle.configByID[this.mapID]
        if (affecteder.teamID == 2 && this.calcDamageFlag && mapConfig.mapType != MapType.Fantasy) {
            this.battleCb({ type: 3, value: { damage1: value } })
        } else if (this.calcDamageFlag && mapConfig.mapType == MapType.Fantasy) {
            this.battleCb({ type: 3, value: { affecteder, value, damageData } })
        }
        this.beAttackAnimation(affecteder.indexID, value, name, damageData.hurtType, damageData.isCrit, damageData.isDodge, damageData.decHpAnimationDelay, affecteder.battlePos)
        if (affecteder.battleAttri.hp < 1) {
            affecteder.battleAttri.hp = 0
            if (affecteder.teamID == TeamID.Team2) {
                if (affecteder.type != MonsterType.Partner) {
                    await this.hideAnimation(affecteder.indexID)
                }
                if (!this.monsterDead[affecteder.indexID]) {
                    this.monsterDead[affecteder.indexID] = true
                    Object.values(affecteder.timerObject).forEach(timerID => {
                        this.timerHandle.clearTimeout(timerID)
                    })
                    affecteder.timers.forEach(timerID => {
                        this.timerHandle.clearTimeout(timerID)
                    })

                    this.monsterAliveAmount -= 1
                    this.battleCb({ type: 2, value: [this.monsterAmount, this.monsterAliveAmount, this.monsterMaxAmount] })
                    if (this.monsterAliveAmount == 0 && this.monsterAmount >= this.monsterMaxAmount) {
                        this.timerHandle.stop()
                        if (this.isEnd == false) {
                            this.isEnd = true

                            this.battleCb({ type: 1, value: { result: BattleResult.Win, monsterAmount: this.monsterAmount, monsterAliveAmount: this.monsterAliveAmount, monsterMaxAmount: this.monsterMaxAmount } })
                        }
                    } else {
                        if (this.monsterAliveAmount < 3) {
                            await this.addMonster()
                        }
                        let triggerEffectData1 = new TriggerEffectDataModel()
                        triggerEffectData1.skillID = damageData.skillID
                        triggerEffectData1.skill = damageData.skill
                        triggerEffectData1.skillLvl = damageData.skillLvl
                        triggerEffectData1.killAttackTimes = killAttackTimes
                        this.battleSkillHandle.triggerEffects(damageData.attacker || this.team1[0], TriggerType.KillEnemy, null, triggerEffectData1)
                    }
                }

            } else if (this.team1.findIndex(p => p && p.battleAttri.hp > 0) == -1) { //人物阵亡
                this.timerHandle.stop()
                if (this.isEnd == false) {
                    this.isEnd = true
                    this.battleCb({ type: 1, value: { result: BattleResult.Lost, monsterAmount: this.monsterAmount, monsterAliveAmount: this.monsterAliveAmount, monsterMaxAmount: this.monsterMaxAmount } })
                }
            }
            Object.values(affecteder.timerObject).forEach(timerID => {
                this.timerHandle.clearTimeout(timerID)
            })
            delete this.monsters[affecteder.indexID]
        }
        if (affecteder.type == MonsterType.Partner) {
            this.fighterNodeUpdate(affecteder.indexID)
            this.playSound("beAttack")
        }
    }

    //找到攻击对象们
    calcHarted(attacker: FighterModel, attackAmount: number, attackRange: [number, number] = null, hatredType: number = 1, highLevel: boolean = false, rangType: number = 1): FighterModel[] {
        if (this.monsterAliveAmount <= 0) {
            return []
        }
        let team = attacker.teamID == TeamID.Team2 ? this.team1 : this.monsters
        let battleConfig = gameConfigHandle.gameConfig.battle
        let hatredPoss = battleConfig.HatredCalcList[hatredType]
        // if (attacker.teamID == 2) {
        //     hatredPoss.battlePos = hatredPoss.battlePos.sort((s1, s2) => {
        //         return s1[0] - s2[0]
        //     })
        // }
        let attackerXY = this.getXY(attacker.battlePos)
        let attackerY = attackerXY.y
        let attackerX = attackerXY.x
        let totalHatred = 0
        let hartreds1 = {} // { 10: [], 9: []}
        let hartreds2 = [] // { 10: [], 9: []}
        let hartreds3 = []
        let alivePos = {}
        let maxHartred = 0
        let hartredPosSet = {}
        Object.values(team).forEach(_fighter => {
            let fighter: any = _fighter
            if (fighter && fighter.battleAttri.hp >= 1) {
                let battlePos = fighter.battlePos
                let { x, y } = this.getXY(fighter.teamID == 1 ? fighter.formationPos : battlePos)
                let value = hatredPoss.battlePos[y][x]
                if (highLevel) {
                    value = value + (battleConfig.highLevelValue[fighter.type] || 0)
                }
                if (!hartredPosSet[value]) {
                    hartredPosSet[value] = []
                }
                hartredPosSet[value].push(fighter)
                totalHatred += value
                if (!hartreds1[value]) {
                    hartreds1[value] = []
                }

                if (maxHartred < value) {
                    maxHartred = value
                }
                hartreds1[value].push({
                    value: value,
                    fighter: fighter
                })
                hartreds2.push({
                    value: value,
                    fighter: fighter
                })
                hartreds3.push({
                    value: fighter.battleAttri.hp,
                    fighter: fighter
                })
                alivePos[fighter.battlePos] = fighter
            }
        })
        if (hatredType == 8) {
            hartreds3.sort((a1, a2) => {
                return a1.value - a2.value
            })
            let defenders: FighterModel[] = hartreds3.slice(0, attackAmount).map(item => {
                return item.fighter
            })
            return defenders
        } else if (hatredType == 7 && hartreds3.length > 0) {
            hartreds3.sort((a1, a2) => {
                return a1.value - a2.value
            })
            let target = hartreds3[0].fighter
            let hitRang = hatredPoss[`hitRang${rangType}`][target.battlePos]
            let rangTarget = []
            hitRang.forEach((hr) => {
                let hitDefenders = []
                for (let p = 0; p < hr.length; p++) {
                    let pos = hr[p];
                    let alive = alivePos[pos]
                    if (alive) {
                        hitDefenders.push(alive)
                    }
                }
                rangTarget.push(hitDefenders)
            })
            rangTarget.sort((a1, a2) => {
                return a2.length - a1.length
            })
            return rangTarget[0]
        }
        if (hatredType == 5) {
            hartreds2.sort((a1, a2) => {
                return a1.value - a2.value
            })
            let target = hartreds2[0].fighter
            let rangTarget = [target]
            Object.entries(team).forEach(_fighter => {
                let fighter: any = _fighter[1]
                if (fighter && fighter.battlePos == target.battlePos - 4) {
                    rangTarget.push(fighter)
                }
            })
            return rangTarget
        }
        else if (hatredType == 3) {
            let defenders: FighterModel[] = []
            let amount = attackAmount
            let entries = Object.entries(hartredPosSet).sort((h1, h2) => Number(h1[0]) - Number(h2[0]))
            for (let i = 0; i < entries.length; i++) {
                let value = entries[i][0]
                let hartredDefenders: any = entries[i][1]
                let subDefenders: FighterModel[] = utils.getRandomArrayNoRepeat(hartredDefenders, attackAmount, this.rand)
                if (subDefenders.length == amount) {
                    subDefenders.forEach(sd => {
                        defenders.push(sd)
                    })
                    break
                } else {
                    subDefenders.forEach(sd => {
                        defenders.push(sd)
                    })
                    amount -= subDefenders.length
                }
            }
            return defenders
        } else if (hatredType == 1) {
            let defenders: FighterModel[] = []
            let amount = attackAmount
            let entries
            if (attacker.teamID == 1) {
                entries = Object.entries(hartredPosSet).sort((h1, h2) => Number(h2[0]) - Number(h1[0]))
            } else {
                entries = Object.entries(hartredPosSet).sort((h1, h2) => Number(h1[0]) - Number(h2[0]))
            }
            for (let i = 0; i < entries.length; i++) {
                let value = entries[i][0]
                let hartredDefenders: any = entries[i][1]
                let subDefenders: FighterModel[] = utils.getRandomArrayNoRepeat(hartredDefenders, attackAmount, this.rand)
                if (subDefenders.length == amount) {
                    subDefenders.forEach(sd => {
                        defenders.push(sd)
                    })
                    break
                } else {
                    subDefenders.forEach(sd => {
                        defenders.push(sd)
                    })
                    amount -= subDefenders.length
                }
            }
            return defenders
        }
        let hartred: any
        try {
            hartred = utils.getOneFromArray(hartreds1[maxHartred] || hartreds2 || hartreds3, this.rand)
        } catch (err) {
            return []
        }
        let defender: FighterModel = hartred.fighter
        if (hatredPoss.IsRand) {
            let defenderTeams: FighterModel[] = []
            for (let i = 0; i < attackAmount && i < hartreds2.length; i++) {
                let randValue = this.rand.intn(totalHatred)
                let j = 0
                while (j < hartreds2.length) {
                    if (randValue <= hartreds2[j].value) {
                        totalHatred -= hartreds2[j].value
                        hartreds2[j].value = 0
                        defenderTeams.push(hartreds2[j].fighter)
                        break
                    }
                    randValue -= hartreds2[j].value
                    j += 1
                }
            }
            return defenderTeams
        }
        let { x, y } = this.getXY(defender.teamID == 1 ? defender.battlePos - 16 : defender.battlePos)
        let { maxY, maxX } = this.getMaxXY()
        if (hatredPoss.RangeType == 2) { //穿透
            let defenderTeams: FighterModel[] = [defender]
            let i = 1
            let j = 1
            while (i <= attackAmount - 1 && y + j <= maxY) {
                if (y + j <= maxY) {
                    let defender = this.team2[this.getBattlePos(x, y + j)]
                    if (defender && defender.battleAttri.hp >= 1) {
                        defenderTeams.push(defender)
                        i += 1
                    }
                }
                j += 1
            }
            return defenderTeams
        } else if (hatredPoss.RangeType == 3) { //十字斩
            let defenderTeams: FighterModel[] = [defender]
            this.fighterBgGlimmerAnimation(this.getBattlePos(x, y), 2)
            for (let i = 1; i <= attackAmount; i++) {
                if (x + i <= maxX) {
                    let defender = this.team2[this.getBattlePos(x + i, y)]
                    this.fighterBgGlimmerAnimation(this.getBattlePos(x + i, y), 2)
                    if (defender && defender.battleAttri.hp >= 1) {
                        defenderTeams.push(defender)
                    }
                }
                if (x - i >= 0) {
                    let defender = this.team2[this.getBattlePos(x - i, y)]
                    this.fighterBgGlimmerAnimation(this.getBattlePos(x - i, y), 2)
                    if (defender && defender.battleAttri.hp >= 1) {
                        defenderTeams.push(defender)
                    }
                }
                if (y + i <= maxY) {
                    let defender = this.team2[this.getBattlePos(x, y + i)]
                    this.fighterBgGlimmerAnimation(this.getBattlePos(x, y + i), 2)
                    if (defender && defender.battleAttri.hp >= 1) {
                        defenderTeams
                            .push(defender)
                    }
                }
                if (y - i >= 0) {
                    let defender = this.team2[this.getBattlePos(x, y - i)]
                    this.fighterBgGlimmerAnimation(this.getBattlePos(x, y - i), 2)
                    if (defender && defender.battleAttri.hp >= 1) {
                        defenderTeams.push(defender)
                    }
                }
            }
            return defenderTeams
        } else if (hatredPoss.RangeType == 4) { //范围
            let rangey = [y - Math.floor(attackRange[1] / 2) + (1 - attackRange[1] % 2), y + Math.floor(attackRange[1] / 2)]
            if (attackRange[1] % 2 == 0) {
                if (this.rand.intn(100) < 50) {
                    rangey = [rangey[0] - 1, rangey[1] - 1]
                }
            }
            if (rangey[1] > maxY) {
                rangey[0] = rangey[0] - (rangey[1] - maxY)
                rangey[1] = maxY
                if (rangey[0] < 0) {
                    rangey[0] = 0
                }
            }
            if (rangey[0] < 0) {
                rangey[1] = rangey[1] + (0 - rangey[0])
                rangey[0] = 0
                if (rangey[1] > maxY) {
                    rangey[1] = maxY
                }
            }
            let rangex = [x - Math.floor(attackRange[0] / 2) + (1 - attackRange[0] % 2), x + Math.floor(attackRange[0] / 2)]
            if (attackRange[0] % 2 == 0) {
                if (this.rand.intn(100) < 50) {
                    rangex = [rangex[0] - 1, rangex[1] - 1]
                }
            }
            if (rangex[1] > maxX) {
                rangex[0] = rangex[0] - (rangex[1] - maxX)
                rangex[1] = maxX
                if (rangex[0] < 0) {
                    rangex[0] = 0
                }
            }
            if (rangex[0] < 0) {
                rangex[1] = rangex[1] + (0 - rangex[0])
                rangex[0] = 0
                if (rangex[1] > maxX) {
                    rangex[1] = maxX
                }
            }
            let _defenderTeams = []
            for (let x = rangex[0]; x <= rangex[1]; x++) {
                for (let y = rangey[0]; y <= rangey[1]; y++) {
                    let battlePos = this.getBattlePos(x, y)
                    let defender = this.team2[battlePos]
                    this.fighterBgGlimmerAnimation(battlePos)
                    if (defender && defender.battleAttri.hp >= 1) {
                        _defenderTeams.push(defender)
                    }
                }
            }
            return _defenderTeams
        }
        return [defender]
    }

    async addMonster(addAmount?, flag: boolean = true) {
        if (!addAmount) {
            let addMax = this.monsterLvl / 8
            if (addMax > 6) {
                addMax = 6
            }
            if (addMax < 2) {
                addMax = 2
            }
            addAmount = utils.getRandomNumber(1, addMax, this.rand)
        }
        if (this.monsterAmount >= this.monsterMaxAmount) {
            return
        }
        if (this.monsterAmount + addAmount >= this.monsterMaxAmount) {
            addAmount = this.monsterMaxAmount - this.monsterAmount
        }
        let emptyPoss = []
        for (let i = 0; i < 12; i++) {
            if (!this.team2[i] || this.team2[i].battleAttri.hp < 1) {
                emptyPoss.push(i)
            }
        }
        if (emptyPoss.length == 0) {
            return
        }
        let mapItemConfig = gameConfigHandle.configByID[this.mapID]
        let poss = utils.getRandomArrayNoRepeat(emptyPoss, addAmount, this.rand)
        let monsters: FighterModel[] = []
        for (let i = 0; i < poss.length; i++) {
            let pos = poss[i]
            let monsterType = MonsterType.Normal
            if (mapItemConfig.mapType == MapType.WorldBoss) {
                monsterType = MonsterType.Boss
            } else if (mapItemConfig.mapType == MapType.Fantasy) {
                monsterType = MonsterType.FantasyMonster
            }
            if (this.monsterAmount == this.monsterMaxAmount - 1) {
                if (mapItemConfig.mapType == MapType.Fantasy) {
                    monsterType = MonsterType.FantasyBoss
                } else {
                    monsterType = MonsterType.Boss
                }
            } else if (mapItemConfig.mapType != MapType.Fantasy) {
                let r = this.rand.intn(100)
                let rate = 10 + this.monsterAmount
                if (rate > 40) {
                    rate = 40
                }
                if (r <= 10 + this.monsterAmount) {
                    monsterType = MonsterType.Elite
                } else {
                    r -= rate
                    let rate1 = this.monsterAmount / 2
                    if (rate1 > 20) {
                        rate1 = 20
                    }
                    if (r < rate1) {
                        monsterType = MonsterType.Lord
                    }
                }
                //除魔卫道不刷白怪
                let bossMapList = gameConfigHandle.gameConfig.base.bossMapList
                if (bossMapList.includes(this.mapID)) {
                    // monsterType = utils.getOneFromArray([MonsterType.Lord, MonsterType.Elite, MonsterType.Elite], this.rand)
                    monsterType = MonsterType.Lord
                }
            }
            let monsterLvl = this.monsterLvl
            if (this.mapType == MapType.Deep) {
                monsterLvl += Math.floor(this.monsterAmount / 2)
            }
            let monster = monsterHandle.createMonster(this.mapID, monsterLvl, monsterType, this.rand)
            monster.indexID = this.remainder + utils.randomString(8, this.rand) + monster.tID
            monster.teamID = TeamID.Team2
            monster.battlePos = pos

            this.monsterAmount += 1
            this.monsters[monster.indexID] = monster
            this.team2[pos] = monster
            this.monsterAliveAmount += 1
            monsters.push(monster)
        }

        if (flag && monsters.length > 0) {
            this.battleUpdate()
            monsters.forEach(monster => {
                this.startAttack(monster)
                if (monster.skills && monster.skills.length) {
                    for (let i = 0; i < monster.skills.length; i++) {
                        let skill = monster.skills[i]
                        this.battleSkillHandle.startUseSkill(monster, skill)
                    }
                }
                if (monster.battleAttri.recoverHp > 0 || monster.battleAttri.recoverHpPer > 0) {
                    this.recoverHp(monster)
                }
            })
        }
    }
    getBattlePos(x, y) {
        return x + y * 5
    }
    getXY(battlePos) {
        let y = Math.floor(battlePos / 4)
        let x = Math.floor(battlePos % 4)
        return { x, y }
    }
    getMaxXY() {
        return { maxX: 4, maxY: 4 }
    }
    clearFighterTimers(fighter: FighterModel) {
        fighter.timers.forEach(timerID => {
            this.timerHandle.clearTimeout(timerID)
        })
        Object.values(fighter.timerObject).forEach(timerID => {
            this.timerHandle.clearTimeout(timerID)
        })
    }
    //获得攻击间隔
    getAttackInterval(attackSpeed, limit: boolean = true) {
        let baseInterval = 5000
        let interval
        if (limit && attackSpeed > 2000) {
            attackSpeed = 2000
        } else if (!limit) {
            if (attackSpeed > 3000) {
                attackSpeed = 3000
            }
        }
        let attackSpeed1 = attackSpeed > 1000 ? 1000 : attackSpeed
        let values = [0, 20]
        let lvl = Math.floor(attackSpeed1 / 10) || 0
        let coe1 = utils.getIncValue(values, lvl)

        let coe2 = 0, coe3 = 0
        if (attackSpeed > 2000) {
            let attackSpeed2 = 1000
            lvl = Math.floor(attackSpeed2 / 20) || 0
            values = [0, 10]
            coe2 = utils.getIncValue(values, lvl)


            let attackSpeed3 = attackSpeed - 2000
            lvl = Math.floor(attackSpeed3 / 10) || 0
            values = [0, 10]
            coe3 = utils.getIncValue(values, lvl)
        } else if (attackSpeed > 1000) {
            let attackSpeed2 = attackSpeed - 1000
            lvl = Math.floor(attackSpeed2 / 20) || 0
            values = [0, 10]
            coe2 = utils.getIncValue(values, lvl)
        }
        interval = (baseInterval - coe1 - coe2 - coe3) / (this.timerHandle.timeCoe || 1)
        return interval
    }

    setTimeCoe(timeCoe) {
        this.timerHandle.timeCoe = timeCoe
    }
    getTimeCoe() {
        return this.timerHandle.timeCoe
    }
    sleep(timeout: number, cb?: (number) => void): Promise<number> {
        return new Promise(async resolve => {
            let duration = timeout
            let timerID = this.timerHandle.setTimeout(() => {
                resolve(timerID)
            }, duration);
            cb && cb(timerID)
        })
    }

    async battleUpdate() {
        if (this.update) {
            await this.update()
        }
    }

    fighterNodeUpdate(id) {
        if (this.update && this.fighterNodes[id]) {
            this.fighterNodes[id].update()
        }
    }
    attackAnimation(id) {
        if (this.update && this.fighterNodes[id]) {
            this.fighterNodes[id].attackAnimation()
        }
    }
    speedAnimation(id) {
        if (this.update && this.fighterNodes[id]) {
            this.fighterNodes[id].speedAnimation()
        }
    }
    cdAnimation(id) {
        if (this.update && this.fighterNodes[id]) {
            this.fighterNodes[id]?.cdAnimation()
        }
    }
    beAttackAnimation(id, value: number, str: string, hurtType: HurtType, isCrit?, isDodge?, decHpAnimationDelay?, battlePos?) {
        if (this.update) {
            if (!this.fighterNodes[id]) {
            } else {
                this.fighterNodes[id].beAttackAnimation(value, str, hurtType, isCrit, isDodge, decHpAnimationDelay)
            }

        }
    }

    skillAttackAnimation(skillID, battlePos, id?) {
        if (this.update && this.fighterNodes[`${battlePos}_${skillID}`]) {
            this.fighterNodes[`${battlePos}_${skillID}`].attackAnimation()
        }
        if (id != null && this.fighterNodes[id]) {
            this.fighterNodes[id].useSkillAnimation(propName[skillID])
        }
    }
    startUseSkillAnimation(skillID, battlePos, duration) {
        if (this.update && this.fighterNodes[`${battlePos}_${skillID}`]) {
            this.fighterNodes[`${battlePos}_${skillID}`].startUseSkill(duration)
        }
    }
    skillTipAnimation(skillID, str) {
        if (this.update && this.fighterNodes[skillID]) {
            this.fighterNodes[skillID].skillTip(str)
        }
    }
    skillStopAnimation(skillID, time) {
        if (this.update && this.fighterNodes[skillID]) {
            this.fighterNodes[skillID].stopSkill(time)
        }
    }
    startAttackAnimation(id, duration) {
        if (this.update) {
            if (!this.fighterNodes[id]) {
            } else {
                this.fighterNodes[id].startAttackAnimation(duration, this.getTimeCoe())
            }
        }
    }
    hideAnimation = async (id) => {
        if (this.update && this.fighterNodes[id]) {
            this.fighterNodes[id].hideAnimation(() => {
                delete this.fighterNodes[id]
            })
        }
        return true
    }

    recoverAnimation(id, value, str: string = '', isCrit?, decHpAnimationDelay?) {
        if (this.update && this.fighterNodes[id]) {
            this.fighterNodes[id].recoverAnimation(value, str, isCrit, decHpAnimationDelay)
        }
    }

    fighterBgGlimmerAnimation = (battlePos, type?: number) => {
        if (this.update) {
            if (this.fighterBgNodes[battlePos]) {
                this.fighterBgNodes[battlePos].glimmer(type)
            }
        }
    }

    playSound(sound) {
        if (this.update) {
        }
    }
}